from sqlalchemy import select, case, literal, false
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import joinedload, join

from apps.functional import schemas
from apps.system.cruds import UserDal
from core.crud import DalBase
from apps.models import FunctionalCaselib, functional_caselib_follow


class CaseLibDal(DalBase):

    def __init__(self, db: AsyncSession):
        super(CaseLibDal, self).__init__()
        self.db = db
        self.model = FunctionalCaselib
        self.schema = schemas.CaselibSimpleOut

    async def follow(self, caselib_id: int, user_id: int, follow: bool):
        users = await UserDal(db=self.db).get_datas(limit=0, id=("in", [user_id]), v_return_objs=True)
        caselib = await self.get_data(caselib_id, v_options=[joinedload(self.model.users)])
        if follow:
            if users:
                caselib.users.clear()
            for user in users:
                caselib.users.add(user)
        else:
            caselib.users.clear()

        await self.flush(caselib)
        return await self.out_dict(caselib)

    async def get_caselibs(self, user_id: int, **kwargs):
        is_follow = case(
            (
                functional_caselib_follow.c.user_id == user_id,
                literal(True)
            ),
            else_=literal(False)
        ).label("is_follow")

        follow_sql = select(FunctionalCaselib, is_follow).join(
            functional_caselib_follow,
            functional_caselib_follow.c.caselib_id == FunctionalCaselib.id
        ).where(
            functional_caselib_follow.c.user_id == user_id,
            FunctionalCaselib.is_delete == false()
        )
        follows = await self.get_datas(v_start_sql=follow_sql, v_use_scalars=False, v_attach_fields=["is_follow"],
                                       v_attach_start_index=1, limit=0)

        all_sql = select(FunctionalCaselib, is_follow).outerjoin(
            functional_caselib_follow,
            FunctionalCaselib.id == functional_caselib_follow.c.caselib_id
        ).where(
            FunctionalCaselib.is_delete == false()
        )
        datas, count = await self.get_datas(v_start_sql=all_sql, v_use_scalars=False, v_attach_fields=["is_follow"],
                                            v_attach_start_index=1, v_return_count=True, **kwargs)

        return datas, count, follows

    async def get_select_options(self) -> list:
        """
        获取选择数据，全部数据
        :return:
        """
        sql = select(self.model)
        queryset = await self.db.scalars(sql)
        return [schemas.CaselibSimpleOut.model_validate(i).model_dump() for i in queryset.all()]
